package math2;

import fem2.Debugger;
import inf.jlinalg.Array1DMatrix;
import inf.jlinalg.Array2DMatrix;
import inf.jlinalg.BLAM;
import inf.jlinalg.IMatrix;
import inf.jlinalg.IVector;
import inf.jlinalg.JArpackSBMGESolver;
import inf.jlinalg.MatrixFormat;
import inf.text.ArrayFormat;
import junit.framework.Assert;

import org.junit.Test;

public class LinAlgUtilitiesTest {

	@Test
	public void testScale() {
		double[] v = new double[] { 1, 2, 3 };
		double[] v_old = v.clone();
		double alpha = 2;
		LinAlgUtilities.scale(3, alpha, v);
		for (int i = 0; i < v.length; i++) {
			Assert.assertEquals(v_old[i] * alpha, v[i], 1e-14);
		}
	}

	@Test
	public void testInvert3x3() {
		double[][] A = new double[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 6, 2, 1 } };
		double[][] Ai = new double[][] { { 7.0 / 9, -(4.0 / 9), 1.0 / 3 },
				{ -(32.0 / 9), 17.0 / 9, -(2.0 / 3) }, { 22.0 / 9, -(10.0 / 9), 1.0 / 3 } };
		LinAlgUtilities.invert3x3(A);
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				Assert.assertEquals(Ai[i][j], A[i][j], MathUtilities.tol14);
			}
		}
	}

	@Test
	public void testBackSolve() {
		double[] A = new double[] { 1, 2, 3, 4, 5, 6, 6, 2, 1 };
		double[] b = new double[] { 1, 0, 0 };
		double[] x = new double[] { 7.0 / 9, -(32.0 / 9), 22.0 / 9 };
		LinAlgUtilities.backSolve(BLAM.NO_TRANSPOSE, A, b);
		for (int i = 0; i < 3; i++) {
			Assert.assertEquals(x[i], b[i], MathUtilities.tol14);
		}
	}

	@Test
	public void testBackSolve2() {
		double[] A = new double[] { 1, 2, 3, 4, 5, 6, 6, 2, 1 };
		double[][] b = new double[][] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
		Array2DMatrix B = new Array2DMatrix(b);
		double[][] X = new double[][] { { 7.0 / 9, -(32.0 / 9), 22.0 / 9 },
				{ -4.0 / 9, 17.0 / 9, -10.0 / 9 }, { 1.0 / 3, -2.0 / 3, 1.0 / 3 } };
		LinAlgUtilities.backSolve(BLAM.NO_TRANSPOSE, A, B);
		System.out.println(MatrixFormat.format(B));
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				Assert.assertEquals(X[j][i], B.get(i, j), MathUtilities.tol14);
			}
		}
	}

	@Test
	public void testAtCB() {
		double[][] a = new double[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 6, 2, 1 } };
		double[][] c = new double[][] { { 2, 5, 5 }, { 9, 2, 4 }, { 4, 7, 2 } };
		double[][] b = new double[][] { { 5, 6, 1 }, { 4, 6, 3 }, { 9, 1, 7 } };
		IMatrix A = new Array2DMatrix(a);
		IMatrix B = new Array2DMatrix(b);
		IMatrix C = new Array2DMatrix(c);
		IMatrix k = new Array2DMatrix(3, 3);
		LinAlgUtilities.atCB(A, B, C, 1.0, k);
		double[][] res = new double[][] { { 827, 735, 458 }, { 727, 580, 397 }, { 825, 629, 453 } };
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				Assert.assertEquals(res[i][j], k.get(i, j), MathUtilities.tol14);
			}
		}
	}

	@Test
	public void testAtCB2() {
		double[][] a = new double[][] { { 1, 2, 3, 3, 6, 8 }, { 4, 5, 6, 1, 6, 3 },
				{ 6, 2, 1, 9, 5, 8 } };
		double[][] c = new double[][] { { 2, 5, 5 }, { 9, 2, 4 }, { 4, 7, 2 } };
		double[][] b = new double[][] { { 5, 6, 1, 1, 8, 5 }, { 4, 6, 3, 7, 3, 4 },
				{ 9, 1, 7, 9, 4, 6 } };
		IMatrix A = new Array2DMatrix(a);
		IMatrix B = new Array2DMatrix(b);
		IMatrix C = new Array2DMatrix(c);
		IMatrix k = new Array2DMatrix(6, 6);
		LinAlgUtilities.atCB(A, B, C, 1.0, k);
		// System.out.println(MatrixFormat.format(k));
		double[][] res = new double[][] { { 827, 735, 458, 744, 793, 728 },
				{ 727, 580, 397, 601, 694, 625 }, { 825, 629, 453, 671, 778, 702 },
				{ 908, 823, 550, 944, 796, 797 }, { 1314, 1042, 765, 1201, 1175, 1122 },
				{ 1395, 1130, 857, 1401, 1178, 1191 } };
		for (int i = 0; i < 6; i++) {
			for (int j = 0; j < 6; j++) {
				Assert.assertEquals(res[i][j], k.get(i, j), MathUtilities.tol14);
			}
		}
	}

	@Test
	public void testAtCB3() {
		double[][] a = new double[][] { { 1, 2, 3, 3, 6, 8 }, { 4, 5, 6, 1, 6, 3 },
				{ 6, 2, 1, 9, 5, 8 } };
		double[][] c = new double[][] { { 2, 5, 5 }, { 9, 2, 4 }, { 4, 7, 2 } };
		double[][] b = new double[][] { { 5, 6, 1, 1, 8, 5, 7 }, { 4, 6, 3, 7, 3, 4, 7 },
				{ 9, 1, 7, 9, 4, 6, 7 } };
		IMatrix A = new Array2DMatrix(a);
		IMatrix B = new Array2DMatrix(b);
		IMatrix C = new Array2DMatrix(c);
		IMatrix k = new Array2DMatrix(6, 7);
		LinAlgUtilities.atCB(A, B, C, 1.0, k);
		// System.out.println(MatrixFormat.format(k));
		double[][] res = new double[][] { { 827, 735, 458, 744, 793, 728, 1050 },
				{ 727, 580, 397, 601, 694, 625, 875 }, { 825, 629, 453, 671, 778, 702, 973 },
				{ 908, 823, 550, 944, 796, 797, 1176 },
				{ 1314, 1042, 765, 1201, 1175, 1122, 1589 },
				{ 1395, 1130, 857, 1401, 1178, 1191, 1715 } };
		for (int i = 0; i < 6; i++) {
			for (int j = 0; j < 7; j++) {
				Assert.assertEquals(res[i][j], k.get(i, j), MathUtilities.tol14);
			}
		}
	}

	@Test
	public void testAtCB4() {
		double[][] g = new double[][] { { -2.309401E00, 0.00000E00, 0.00000E00, 0.00000E00 },
				{ 0.00000E00, -2.309401E00, 0.00000E00, 0.00000E00 },
				{ 0.00000E00, 0.00000E00, -2.309401E00, -2.309401E00 } };
		double[][] c = new double[][] { { 2.197802E00, 6.593407E-01, 0.00000E00 },
				{ 6.593407E-01, 2.197802E00, 0.00000E00 }, { 0.00000E00, 0.00000E00, 7.692308E-01 } };
		double[][] b = new double[][] {
				{ -7.886751E-01, 0.00000E00, 7.886751E-01, 0.00000E00, 2.113249E-01, 0.00000E00,
						-2.113249E-01, 0.00000E00 },
				{ 0.00000E00, -7.886751E-01, 0.00000E00, -2.113249E-01, 0.00000E00, 2.113249E-01,
						0.00000E00, 7.886751E-01 },
				{ -7.886751E-01, -7.886751E-01, -2.113249E-01, 7.886751E-01, 2.113249E-01,
						2.113249E-01, 7.886751E-01, -2.113249E-01 } };
		IMatrix G = new Array2DMatrix(g);
		IMatrix C = new Array2DMatrix(c);
		IMatrix B = new Array2DMatrix(b);
		IMatrix k = new Array2DMatrix(4, 8);
		LinAlgUtilities.atCB(G, B, C, 1.0, k);
		System.out.println(MatrixFormat.format(k));
		// double[][] res = new double[][] {
		// { 827, 735, 458, 744, 793, 728, 1050 },
		// { 727, 580, 397, 601, 694, 625, 875 },
		// { 825, 629, 453, 671, 778, 702, 973 },
		// { 908, 823, 550, 944, 796, 797, 1176 },
		// { 1314, 1042, 765, 1201, 1175, 1122, 1589 },
		// { 1395, 1130, 857, 1401, 1178, 1191, 1715 } };
		// for (int i = 0; i < 6; i++) {
		// for (int j = 0; j < 7; j++) {
		// Assert.assertEquals(res[i][j], k.get(i, j), MyLinAlg.tol14);
		// }
		// }
	}

	@Test
	public void testGtHiG() {
		double[][] g = new double[][] { { 1, 2, 3, 3, 6, 8 }, { 4, 5, 6, 1, 6, 3 },
				{ 6, 2, 1, 9, 5, 8 } };
		IMatrix G = new Array2DMatrix(g);

		double[][] h = new double[][] { { 2, 5, 5 }, { 9, 2, 4 }, { 4, 7, 2 } };
		Array1DMatrix H = Array1DMatrix.createRowMajor(3, 3);
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				H.set(i, j, h[i][j]);
			}
		}

		IMatrix k = new Array2DMatrix(6, 6);
		LinAlgUtilities.gtHiG(G, H, 1.0, k);

		double[][] res = new double[][] {
				{ -1.11521, 1.86636, 3.63134, 0.456221, 6.12903, 7.70046 },
				{ 3.30876, 1.19816, 0.788018, 5.73733, 3.77419, 6.20276 },
				{ 5.42396, 1.3318, 0.156682, 8.28111, 3.64516, 6.5023 },
				{ -4.32719, 3.70046, 7.553, -6.18433, 7.80645, 5.94931 },
				{ 4.22581, 3.74194, 4.32258, 5.22581, 7.3871, 8.3871 },
				{ 1.01382, 5.57604, 8.24424, -1.41475, 9.06452, 6.63594 } };
		for (int i = 0; i < 6; i++) {
			for (int j = 0; j < 6; j++) {
				Assert.assertEquals(res[i][j], k.get(i, j), MathUtilities.tol5);
			}
		}
	}

	@Test
	public void testCreateLambdaArray() {
		double[] l = MathUtilities.createLambdaArray(0.0, 0.1, 1.0, 0.2, 1.9, 0.1, 2);
		System.out.println(ArrayFormat.format(l));
	}

	@Test
	public void testBCBt() {
		double[][] b = new double[][] { { 1, 1 }, { 0, 1 } };
		double[][] c = new double[][] { { 0.5, 0 }, { 0, 0.3 } };
		IMatrix B = new Array2DMatrix(b);
		IMatrix C = new Array2DMatrix(c);
		IMatrix tmp = new Array2DMatrix(2, 2);
		LinAlgUtilities.bCBt(B, C, 1.0, tmp);
		Debugger.watch(tmp);
	}

	@Test
	public void testEigenvalues() {
		double[][] a = new double[][] { { 1, 1, 0 }, { 1, 1, 0 }, { 0, 0, 1 } };
		double[][] b = new double[][] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
		IMatrix A = new Array2DMatrix(a);
		IMatrix B = new Array2DMatrix(b);

		JArpackSBMGESolver se = LinAlgUtilities.createEigenvalueSolver(A, B);

		Debugger.watch((IVector) se.getEigenvalues());
	}
}
